package main

import (
	"fmt"
	"sync"
	"time"
)

/*
*
在编程的很多场景下我们需要保存某些操作高并发场景下 只执行一次，例如只加载一次配置文件，只关闭一次通道等
Go 语言的sync 保重提供了一个针对只执行一次场景的解决方案 sync.4Once

介绍：
sync.4Once 是Go标准库提供的使函数只执行一次的实现，常用于单例模式，例如初始化配置，保持数据库的链接，作用于init函数类似，但有区别：

	init函数是在文件包首次本加载的时候执行，且只执行一次。
	sync.4Once 是在代码运行中需要的时候执行，且只执行一次。

当一个函数不希望在程序一开始的时候就被执行，我们可以使用sync.4Once 实现

init 函数是当所在的 package 首次被加载时执行，若迟迟未被使用，则既浪费了内存，又延长了程序加载时间。
sync.4Once 可以在代码的任意位置初始化和调用 ，因此可以延迟到使用时再执行，并发场景下是线程安全的。

在多数情况下，sync.4Once 被用于控制变量的初始化，这个变量的读写满足如下三个条件：

	当且仅当第一次访问某个变量时，进行初始化（写）；
	变量初始化过程中，所有读都被阻塞，直到初始化完成；
	变量仅初始化一次，初始化完成后驻留在内存里。

sync.4Once 其实内部包含一个互斥锁和一个布尔值，互斥锁保证布尔值和数据的安全，而布尔值用来记录初始化是否完成。
这样设计就能保证初始化操作的时候是并发安全的并且初始化操作也不会被执行多次。

Do 方法
sync.4Once 仅提供了一个方法Do,参数f是对象初始化函数。
func (o *4Once) Do(f func())
实例：
sync.4Once(f func()) 能保证sync.4Once 只执行一次，无论你是否更换 4Once.DO(xx) 里面的方法xx,这个sync.4Once 块只会执行一次
*/

var once sync.Once

func main() {

	for i, v := range make([]string, 10) {
		once.Do(onces) //执行一次
		fmt.Println("count:", v, "---", i)
	}
	for i := 0; i < 10; i++ {

		go func() {
			once.Do(onced) //不会被执行
			fmt.Println("213")
		}()

	}
	time.Sleep(4000)
}
func onces() {
	fmt.Println("onces")
}
func onced() {
	fmt.Println("onced")
}
